/**
 * @author alex
 */

Namespace("sketch.commands");

(function() {
    var fwk = sketch.framework,
        cmd = sketch.commands,
        ui = sketch.ui,
        common = sketch.ui.common,
        iphone = ui.iphone;

    var AddElementCommand = klass(sketch.framework.commands.Command, {
        _constructor: function(id, app) {
            this.app = app;
        },
        execute: function() {
            this.element = this.createElement();
            this.app.activePage.view.layer2.add(this.element);
        },
        rollback: function() {
            this.app.activePage.view.layer2.remove(this.element);
        },
        createElement: function() {
        }
    });

    var register = function(id, C) {
        cmd[id] = C;
    };

    sketch.commands.registerCommands = function() {
        register('iphone.phone', klass(AddElementCommand, {
            createElement: function() {
                return new ui.iphone.phone();
            }
        }));

        register('iphone.button', klass(AddElementCommand, {
            createElement: function() {
                return new ui.common.BarItem();
            }
        }));

        register('common.checkbox', klass(AddElementCommand, {
            createElement: function() {
                return new ui.common.CheckBox();
            }
        }));

        register('common.text', klass(AddElementCommand, {
            createElement: function() {
                return new ui.common.TextArea();
            }
        }));

        register('common.container', klass(AddElementCommand, {
            createElement: function() {
                var element = new ui.common.DockPannel(true);
                element.width(300);
                element.height(200);
                return element;
            }
        }));

        cmd.PropertyChanged = klass(fwk.commands.Command, {
            _constructor: function(property) {
                this.property = property;
            },
            execute: function() {
                if (this.oldValue === undefined){
                    this.oldValue = this.property();
                }
                this.property(this.value);
            },
            rollback: function() {
                this.property(this.oldValue);
            }
        });

        cmd.Composite = klass(fwk.commands.Command, {
            _constructor: function(/*Array*/commands, /*View*/view) {
                this._commands = commands;
                this._view = view;
                this.name("composite");
            },

            canExecute: function(){
                var result = true;

                each(this._commands, function(c){
                    if (!c.canExecute()){
                        result = false;
                        return false;
                    }
                });

                return result;
            },

            execute: function() {
                this._view.unselectAll();
                this._view.selectionMode("add");
                for (var i = 0, len = this._commands.length; i < len; ++i) {
                    var command = this._commands[i];
                    command.execute();
                }
                this._view.selectionMode("new");
            },

            rollback: function() {
                this._view.unselectAll();
                this._view.selectionMode("add");
                for (var i = 0, len = this._commands.length; i < len; ++i) {
                    var command = this._commands[i];
                    command.rollback();
                }
                this._view.selectionMode("new");
            }
        });

        cmd.MoveResizeElement = klass(fwk.commands.Command, {
            _constructor: function(element, newSize, parent, index) {
                this.element = element;
                this.newSize = newSize;
                this.newParent = parent;
                this.oldParent = element.parent();
                this.newIndex = index;
                this.name("moveResize");
            },

            canExecute: function(){
                if (this.oldParent !== this.newParent) {
                    if (!this.oldParent.canRemove(this.element)){
                        return false;
                    }

                    if (this.newIndex == undefined) {
                        if (!this.newParent.canAdd(this.element)) {
                            return false;
                        }
                    } else {
                        if (!this.newParent.canInsert(this.element, this.newIndex)) {
                            return false;
                        }
                    }
                }

                return true;
            },

            execute: function(isRedo) {
                this.oldValue = this.element.getBoundaryRect();
                this.oldIndex = this.element.index();

                if (this.oldParent !== this.newParent) {
                    this.oldParent.remove(this.element);

                    if (this.newIndex == undefined) {
                        this.newParent.add(this.element);
                    } else {
                        this.newParent.insert(this.element, this.newIndex);
                    }
                } else {
                    if (this.newIndex != undefined) {
                        this.newParent.changePosition(this.element,  this.newIndex);
                    }
                }
                this.element.resize(this.newSize);
                this.oldParent.view().makeSelection([this.element]);
            },
            rollback: function() {
                if (this.oldParent !== this.newParent) {
                    this.newParent.remove(this.element);

                    if (this.newIndex == undefined) {
                        this.oldParent.add(this.element);
                    } else {
                        this.oldParent.insert(this.element, this.oldIndex);
                    }
                } else {
                    if (this.newIndex != undefined) {
                        this.oldParent.changePosition(this.element,  this.oldIndex);
                    }
                }
                this.element.resize(this.oldValue);
                this.element.view().makeSelection([this.element]);
            }
        });
        
        cmd.Copy = klass(fwk.commands.Command, {
            _constructor: function(selection) {
                this._selection = selection;

                this.description("Copy");
                this.name("copy");
                this.transparent(true);
            },

            execute: function() {
                if (!this._selection || this._selection.length === 0){
                    return false;
                }

                fwk.clipboard.value({
                    originalParent: this._selection[0].parent(),
                    originalSelection: this._selection,
                    cloneSelection: toArray(this._selection, function(element){ return element.clone(); }),
                    action: "copy"});
            },

            rollback: function() {
            }
        });

        cmd.Paste = klass(fwk.commands.Command, {
            _constructor: function(parent) {
                this._wantedParent = parent;

                this.description("Paste");
                this.name("paste");
            },

            _getData: function(){
                return this._data !== undefined ? this._data : fwk.clipboard.value();
            },

            canExecute: function(){
                var data = this._getData();

                if (!data || !data.cloneSelection || data.cloneSelection.length === 0) {
                    return false;
                }

                var result = true;
                each(data.cloneSelection, function(clone){
                    if (!data.originalParent.canAdd(clone)){
                        result = false;
                        return false;
                    }
                });

                return result;
            },

            execute: function() {
                var data = this._getData();

                if (this._data === undefined) {
                    this._cloneSelection = toArray(data.cloneSelection, function(element){ return element.clone(); });
                    if (data.action === "copy") {
                        each(this._cloneSelection, function(clone){
                            clone.left(clone.left() + clone.width() + 5);
                        });
                    }
                }

                var that = this;
                each(this._cloneSelection, function(clone){
                    //TODO: enable pasting into containers
                    //var parent = that._wantedParent.canAccept(clone) ? that._wantedParent : data.originalParent;
                    var parent = data.originalParent;
                    parent.add(clone);
                    that._newParent = parent;
                });

                var view = this._newParent.view();
                if (data.action === "copy"){
                    this._originalSelection = view.getSelection();
                }
                view.makeSelection(this._cloneSelection);

                this._data = data;
            },

            rollback: function() {
                var data = this._data;
                var that = this;
                if (this._originalSelection) {
                    that._newParent.view().makeSelection(this._originalSelection);
                }
                else {
                    that._newParent.view().unselectAll();
                }
                each(this._cloneSelection, function(clone){
                    that._newParent.remove(clone);
                });
            }
        });

        cmd.Cut = klass(fwk.commands.Command, {
            _constructor: function(selection) {
                this._selection = selection;

                this.description("Cut");
                this.name("cut");
            },

            canExecute: function(){
                if (!this._selection || this._selection.length === 0){
                    return false;
                }

                var parent = this._selection[0].parent();
                var result = true;

                each(this._selection, function(element){
                    if (!parent.canRemove(element)) {
                        result = false;
                        return false;
                    }
                });

                return result;
            },

            execute: function() {
                this._originalParent = this._selection[0].parent();
                this._originalView = this._originalParent.view();

                fwk.clipboard.value({
                    originalSelection: this._selection,
                    cloneSelection: toArray(this._selection, function(element){ return element.clone(); }),
                    originalParent: this._originalParent,
                    action: "cut"});

                this._originalView.unselectAll();
                var that = this;
                each(this._selection, function(element){
                    that._originalParent.remove(element);
                });
            },

            rollback: function() {
                var that = this;
                each(this._selection, function(element){
                    that._originalParent.add(element);
                });
                this._originalView.makeSelection(this._selection);
            }
        });

        cmd.Delete = klass(fwk.commands.Command, {
            _constructor: function(selection, propertyDesigner, actionDesigner){
                this._selection = selection;
                this._propertyDesigner = propertyDesigner;
                this._actionDesigner = actionDesigner;

                this.name("delete");
                this.description("Delete");
            },

            canExecute: function(){
                if (!this._selection || this._selection.length === 0){
                    return false;
                }

                var parent = this._selection[0].parent();
                var result = true;

                each(this._selection, function(element){
                    if (!parent.canRemove(element)) {
                        result = false;
                        return false;
                    }
                });

                return result;
            },

            execute: function(){
                var parent = this._selection[0].parent();
                this._parent = parent;
                parent.view().unselectAll();
                each(this._selection, function(element){
                    parent.remove(element);
                });
                this._propertyDesigner.clear();
                this._actionDesigner.clear();
            },

            rollback: function(){
                var that = this;
                each(this._selection, function(element){
                    that._parent.add(element);
                });
                this._parent.view().makeSelection(this._selection);

            }
        });

        cmd.Duplicate = klass(fwk.commands.Command, {
            _constructor: function(selection){
                this._selection = selection;

                this.name("duplicate");
                this.description("Duplicate");
            },

            canExecute: function(){
                if (!this._selection || this._selection.length === 0){
                    return false;
                }

                var parent = this._selection[0].parent();
                var result = true;

                each(this._selection, function(clone){
                    if (!parent.canAdd(clone)){
                        result = false;
                        return false;
                    }
                });

                return result;
            },

            execute: function(){
                var parent = this._selection[0].parent();
                this._parent = parent;
                this._cloneSelection = toArray(this._selection, function(element){ return element.clone(); });

                each(this._cloneSelection, function(element){
                    element.left(element.right() + 5);
                    parent.add(element);
                });
                parent.view().makeSelection(this._cloneSelection);
            },

            rollback: function(){
                var that = this;
                this._parent.view().makeSelection(this._selection);
                each(this._cloneSelection, function(element){
                    that._parent.remove(element);
                });

            }
        });

        cmd.ChangeZOrder = klass(fwk.commands.Command, {
            _constructor: function(selection, mode){
                this._selection = selection;
                this._mode = mode;

                switch (mode){
                    case "front":
                        this.name("bringToFront");
                        this.description("Bring To Front");
                        break;
                    case "back":
                        this.name("sendToBack");
                        this.description("Send To Back");
                        break;
                    case "forward":
                        this.name("bringForward");
                        this.description("Bring Forward");
                        break;
                    case "backward":
                        this.name("sendBackward");
                        this.description("Send Backward");
                        break;
                }
            },

            execute: function(){
                if (!this._selection || this._selection.length === 0){
                    return false;
                }

                this._originalOrder = toArray(this._selection, function(e){
                    return {element: e, order: e.parent().getChildren().positionOf(e) }
                });

                var allChildren = this._selection[0].parent().getChildren();
                var max = allChildren.count() - 1;

                switch (this._mode) {
                    case "front":
                        each(this._selection, function(e){
                            e.parent().changePosition(e, max);
                        });
                        break;
                    case "back":
                        each(this._selection, function(e){
                            e.parent().changePosition(e, 0);
                        });
                        break;
                    case "forward":
                        each(this._selection, function(e){
                            var newPos = allChildren.positionOf(e) + 1;
                            if (newPos > max) {
                                newPos = max;
                            }
                            e.parent().changePosition(e, newPos);
                        });
                        break;
                    case "backward":
                        each(this._selection, function(e){
                            var newPos = allChildren.positionOf(e) - 1;
                            if (newPos < 0) {
                                newPos = 0;
                            }
                            e.parent().changePosition(e, newPos);
                        });
                        break;
                }

                this._selection[0].view().makeSelection(this._selection);
            },

            rollback: function(){
                each(this._originalOrder, function(e){
                    e.element.parent().changePosition(e.element, e.order);
                });
                this._selection[0].view().makeSelection(this._selection);
            }
        });

        cmd.Move = klass(fwk.commands.Command, {
            _constructor: function(selection, direction){
                this._selection = selection;
                this._direction = direction;

                switch (direction){
                    case "up":
                        this.name("moveUp");
                        this.description("Move Up");
                        break;
                    case "down":
                        this.name("moveDown");
                        this.description("Move Down");
                        break;
                    case "left":
                        this.name("moveLeft");
                        this.description("Move Left");
                        break;
                    case "right":
                        this.name("moveRight");
                        this.description("Move Right");
                        break;
                }
            },

            execute: function(){
                if (!this._selection || this._selection.length === 0){
                    return false;
                }

                this._originalPositions = toArray(this._selection, function(e){
                    return {element: e, position: e.position() }
                });

                var offset = 1;

                switch (this._direction) {
                    case "up":
                        each(this._selection, function(e){
                            e.top(e.top() - offset);
                        });
                        break;
                    case "down":
                        each(this._selection, function(e){
                            e.top(e.top() + offset);
                        });
                        break;
                    case "left":
                        each(this._selection, function(e){
                            e.left(e.left() - offset);
                        });
                        break;
                    case "right":
                        each(this._selection, function(e){
                            e.left(e.left() + offset);
                        });
                        break;
                }

                this._selection[0].view().makeSelection(this._selection);
            },

            rollback: function(){
                each(this._originalPositions, function(e){
                    e.element.position(e.position);
                });
                this._selection[0].view().makeSelection(this._selection);
            }
        });
    };

})(sketch);
